package cn.itsource.blog.service.impl;

import cn.itsource.blog.domain.Article;
import cn.itsource.blog.mapper.ArticleMapper;
import cn.itsource.blog.query.ArticleQuery;
import cn.itsource.blog.service.IArticleService;
import cn.itsource.vo.ArticleVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
// Transactional：用来控制事务的注解；readOnly：只读；propagation：事务传播机制
//  Propagation.SUPPORTS：支持当前事务，如果没有当前事务，就以非事务方法执行
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
@CacheConfig(cacheNames="articleRecommend") // CacheConfig：共享的一些常见缓存设置  类上加注解，可以全局使用（下面就可以不用写cacheNames，但是key不能在类上加）
public class ArticleServiceImpl implements IArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private MongoTemplate mongoTemplate;


    @Transactional
    @Override
    @CacheEvict(key = "'articles'")
    public void add(Article article) {
        // mysql的添加
        articleMapper.add(article);

        if (article.getArticleRecommend() == 1){
            articleMapper.addRecommend(article);
        }

        // mongoDB的添加
        mongoTemplate.save(article);
    }

    @Transactional
    @Override
    @CacheEvict(key = "'articles'")
    public void update(Article article) {

        // 设置更新时间为当前系统时间
        article.setUpdateTime(new Date());
        // mysql的修改
        articleMapper.update(article);
        articleMapper.delRecommend(article.getId());
        if (article.getArticleRecommend() == 1){
            articleMapper.addRecommend(article);
        }

        // mongoDB的修改
        // 不能直接通过_id删除，因为前端传过来的数据是mysql数据库的，没有_id字段（值为null），所以不获取mongoDB数据库的_id没有办法进行删除操作
        Query query = new Query(Criteria.where("id").is(article.getId())); // 获取数据库的id，因为是主键自增长，所以是唯一的
        Article mongoArticle = mongoTemplate.findOne(query, Article.class); // 通过唯一的id获取到article对象
        if (mongoArticle != null) { // 判断传入的article对象在MongoDB中是否存在
            article.set_id(mongoArticle.get_id()); // 存在的话就设置article对象的_id为MongoDB的_id
        }
        mongoTemplate.save(article); // 如果存在对象就会根据_id进行修改。没有就会添加

    }

    @Transactional
    @Override
    @CacheEvict(key = "'articles'")
    public void delete(Long id) {
        // mysql的删除
        articleMapper.delete(id);
        // mongoDB的删除
        Query query = new Query(Criteria.where("id").is(id));


        articleMapper.delRecommend(id);

        mongoTemplate.remove(query, Article.class);
    }

    @Override
    public Article getOne(Long id) {
        return articleMapper.getOne(id);
    }

    @Override
    public List<Article> getAll() {
        return articleMapper.getAll();
    }

    @Transactional
    @Override
    @CacheEvict(key = "'articles'")
    public void patchDelete(Long[] ids) {
        for (Long id : ids) {
            // 执行delete方法
           delete(id);
        }
    }

    @Override
    public PageInfo<Article> pageQuery(ArticleQuery query) {
        //原生的写法：1.先查询总页数  2.再根据分页的信息查询当前页的数据
        //PageHelper的写法：开启分页
//                PageHelper.startPage(当前页,每页显示的条数);
        PageHelper.startPage(query.getCurrentPage(), query.getPageSize());
        //分页查询：只要开启了分页，它会帮助我们做什么事情？
        //1.先查询总数量  //2.根据application.yml中驱动名自动实现分页，如果是mysql就用limit
        //3.自动计算limit的第一个值：limit a,b [a = 当前页的起始下标 = (当前页-1)*每页显示的条数]
//        List<Emp> emps = empMapper.pageQuery(empQuery);
        List<Article> list = articleMapper.pageQuery(query);
        return new PageInfo(list);
    }

    @Override
    public List<ArticleVo> countNumberByType() {
        return articleMapper.countNumberByType();
    }

    @Override
    public List<ArticleVo> countNumberByTime() {
        return articleMapper.countNumberByTime();
    }

    @Override
    public List<Article> getRelatedArticles(Long id) {
        return articleMapper.getRelatedArticles(id);
    }

    @Override
    public ArticleVo getArticles(Long id) {
        List<Article> articles = articleMapper.getArticles(id);
        ArticleVo articleVo = new ArticleVo();
        articleVo.setArticles(articles);
        articleVo.setArticleTypeName(articles.get(0).getArticleTypeName()); // 获取文章类型名称
        return articleVo;

    }

    @Override
    //  Cacheable：表示该方法会开启缓存， 每次调用类型树方法都先清除一次缓存，更节约内存空间
    @Cacheable(cacheNames="articleRecommend" ,key = "'articles'")
    public List<Article> getArticleRecommend() {
        return getArticleRecommendFromDB();
    }

    public List<Article> getArticleRecommendFromDB() {
        List<Article> articles = articleMapper.getAllArticleRecommend();
        for (Article article : articles) {
            if ( article.getArticleName().length() > 12){
                article.setArticleName(article.getArticleName().substring(0,12) + "...");
            }else{
                article.getArticleName();
            }
            if ( article.getArticleRemark().length() > 12){
                article.setArticleRemark(article.getArticleRemark().substring(0,12)+"...");
            }else{
                article.getArticleRemark();
            }
        }
        return articles;
    }

    @Override
    public Integer getArticleRecommendCount() {
        return articleMapper.getArticleRecommendCount();
    }





}
